package dao

import (
	"OJCenter/dao/mysql"
	"OJCenter/dao/redis"
	"OJCenter/global"
	"OJCenter/idl"
	"encoding/json"
	"errors"
	"strconv"
)

const SubmissionPre = "s:"

type SubmissionInfo struct {
	mysql *mysql.MysqlDao
	redis *redis.RedisDao
}

func NewSubmissionInfo() (*SubmissionInfo, error) {
	m, err := mysql.NewMysqlDao()
	if err != nil {
		return nil, err
	}
	r, err := redis.NewRedisDao()
	if err != nil {
		return nil, err
	}
	return &SubmissionInfo{
		mysql: m,
		redis: r,
	}, nil
}

func (u *SubmissionInfo) GetSubmissionCodeInfoOSS(sid int64) (code *[]byte, err error) {
	return nil, nil
}

// GetSubmissionCidFromCache 只有contest才会去redis存储
// 因为只有一个竞赛,所以用uid作key
func (u *SubmissionInfo) GetSubmissionCodeInfoFromCache(uid int64, cid int64, pid int64) (*[]idl.Submission, error) {
	_subs, err := u.redis.SGet(SubmissionPre + strconv.Itoa(int(cid)) + ":" + strconv.Itoa(int(uid)) + ":" + strconv.Itoa(int(pid)))
	if err != nil {
		subs, err := u.GetSubmissionInfoWithDataByUCPId(uid, cid, pid)
		if err != nil {
			global.Logger.Errorf("GetSubmissionPidsFromCache failed,err:%v", err)
			return nil, err
		}
		return subs, nil
	}
	subs := make([]idl.Submission, len(_subs))
	for i, _sub := range _subs {
		err := json.Unmarshal([]byte(_sub), &subs[i])
		if err != nil {
			global.Logger.Errorf("uid:%v,cid:%v,pid:%v,unmarshal failed", uid, cid, pid)
		}
	}
	return &subs, nil
}

func (u *SubmissionInfo) GetSubmissionInfoWithDataByUCPId(uid, cid, pid int64) (*[]idl.Submission, error) {
	var subs []idl.Submission
	err := u.mysql.Orm.Where("uid =? and cid = ? and pid = ?", uid, cid, pid).Find(&subs)
	if err != nil {
		return nil, err
	}
	pros := make([]string, len(subs))
	for i, ret := range subs {
		_ret, err := json.Marshal(ret)
		if err != nil {
			global.Logger.Errorf("uid:%v,cid:%v,pid:%v,marshal failed", uid, cid, pid)
			continue
		}
		pros[i] = string(_ret)
	}
	_, err = u.redis.SSet(SubmissionPre+strconv.Itoa(int(cid))+":"+strconv.Itoa(int(uid))+":"+strconv.Itoa(int(pid)), pros...)
	if err != nil {
		global.Logger.Errorf("Submission load redis failed,err:%v", err)
	}

	return &subs, nil
}
func (u *SubmissionInfo) GetSubmissionInfosFromDataByUPId(uid, pid int64) (*[]idl.Submission, error) {
	var subs []idl.Submission
	err := u.mysql.Orm.Where("uid =? and pid = ?", uid, pid).Find(&subs)
	if err != nil {
		return nil, err
	}
	return &subs, nil
}

func (u *SubmissionInfo) DeleteSubmissionInfo(info *idl.Submission) error {
	if info == nil {
		return errors.New("info is nil")
	}
	_, err := u.redis.DelKey(SubmissionPre + strconv.Itoa(int(info.Cid)) + ":" + strconv.Itoa(int(info.Uid)) + ":" + strconv.Itoa(int(info.Pid)))
	if err != nil {
		global.Logger.Errorf("Submission load redis failed,err:%v", err)
	}
	cond := make(map[string]interface{})
	cond["cid"] = info.Cid
	cond["pid"] = info.Pid
	cond["uid"] = info.Uid
	sum, err := u.mysql.DeleteInfos("submission", &cond)
	if err != nil || sum == 0 {
		return errors.New("delete Submission failed")
	}
	return nil
}

func (u *SubmissionInfo) UpdateSubmissionInfo(info *map[string]interface{}) error {
	if info == nil {
		return errors.New("info is nil")
	}
	var sub idl.Submission
	_, err := u.mysql.Orm.Where("Sid = ?", (*info)["sid"]).Get(&sub)
	if err != nil {
		global.Logger.Errorf("cant find submisson,err:%v", err)
		return err
	}
	_, err = u.redis.DelKey(SubmissionPre + strconv.Itoa(int(sub.Cid)) + ":" + strconv.Itoa(int(sub.Uid)))
	if err != nil {
		global.Logger.Errorf("Submission load redis failed,err:%v", err)
	}

	sum, err := u.mysql.Orm.Table("submission").Update(info, &sub)
	if err != nil || sum == 0 {
		return errors.New("update Submission failed")
	}
	return nil
}

func (u *SubmissionInfo) InsertSubmissionInfo(info *idl.Submission) error {
	sum, err := u.mysql.InsertInfos("submission", info)
	if err != nil || sum == 0 {
		return err
	}
	return nil
}
